<?php
namespace Core\Libs\MasterController;

class MasterControllerException {

	
}

class MasterController extends \Core\Libs\ExtendObject\ExtendObject {

	protected $controllerName = '';
	protected $actionOfController = '';
	protected $classController = '';
	protected $controllerPath = '';
	protected $autoRender = TRUE;

	protected $viewName = '';
	protected $classView = '';
	protected $actionOfView = '';
	protected $varsViewClass = array();
	protected $varsViewDesign = array();
	protected $varsLayout = array();
	protected $noRender = FALSE;

	private $models = array();
	private $components = array('Session', 'Exception', 'Teste' => array('alias' => 'Auth', 'params' => array()));

	protected $Component = NULL;
	protected $Model = NULL;

	private $actionOutput = NULL;
	private $outputContent = NULL;
	private $arrayCallbackMethods = array(
											'beforeFilter',
											'afterFilter',
											'beforeRender',
											'afterRender',
											'beforeSave',
											'afterSave',
											'beforeUpdate',
											'afterUpdate', 
											'beforeDelete', 
											'afterDelete', 
											'beforeSelect', 
											'afterSelect'
										);

	private function &setComponent($Component = NULL) {

		self::$Component = $Component;
	}

	final public function &getComponent() {

		return $this->Component;
	}

	final public function &setComponents(&$components) {

		$this->components = $components;
	}

	final public function &getComponents() {

		return $this->components;
	}

	public function __construct(){

	}

	public function __destruct() {

		unset($this);
	}

	private function &_inputCallbacksOfController() {

		
	}

	private function &_inputCallbacksOfComponents() {

		
	}

	private function &_outputCallbacksOfController() {

		
	}

	private function &_outputCallbacksOfComponents() {

		
	}

	final public function callViewClass() {

		
	}

	final public function setActionOutput($actionOutput = NULL) {

		$this->actionOutput = $actionOutput;
	}

	final public function &getActionOutput() {

		return $this->controlerOutput;
	}

	final public function setOutputContent($outputContent = NULL) {

		$this->outputContent = $outputContent;
	}

	final public function &getOutputContent() {

		return $this->outputContent;
	}

	final public static function getPropertyValue($propertyName, $context = NULL, $isStatic = NULL, $namespace = NULL, $reverse = TRUE, $first = FALSE) {

		$Controller = parent::getController();

		if(is_object($Controller)) {

			$ReflectionObject =& new \Core\Libs\Reflection\ReflectionObject(&$Controller);
			return $ReflectionObject->getProperty($propertyName)->getValue($context, $isStatic, $namespace, $reverse, $first);
		}

		else {

			throw \Core\Uses\exception('Error: Controller não é um objeto.', E_WARNING, 100, __FILE__, __LINE__);
		}
	}

	private function &getPostsOfModels() {

		$arrayPostsChecked = array();
		$match = array();
		$app =& substr(str_replace('\\', '.', parent::getNamespaceBase()), 0, -1);

		foreach($_POST as $i => &$post) {

			if(preg_match('/model(?:s)?\.(.+)/i', str_replace('_', '.', &$i), &$match)) {

				if(preg_match('/^((?:[a-zA-Z0-9\_\-]+\.)(?:[a-zA-Z0-9\_\-]+\.)?(?:[a-zA-Z0-9\_\-]+\.)?(?:[a-zA-Z0-9\_\-]+\.)?(?:[a-zA-Z0-9\_\-]+\.)?)?([a-zA-Z0-9\_\-]+)\.([a-zA-Z0-9\_\-]+)$/', &$match[1], &$match)) {

					$match[2] =& \Core\Libs\Extend\Config::getNamespace($match[2], 1);
					$match[3] =& str_replace('-', '_', &$match[3]);

					if(!empty($match[1])) {

						$appFull = \Core\Libs\Extend\Config::getNamespace(substr(&$match[1], 0, -1), 1);
						$arrayPostsChecked[$appFull][$match[2]][$match[3]] =& $post;
					}

					else {

						$arrayPostsChecked[$app][$match[2]][$match[3]] =& $post;
					}
				}
			}
		}

		self::_setData(&$arrayPostsChecked);
	}

	private function &_initAjaxRequest() {

		$arrayData = $_POST['_CoreConfigRequest']['data'];
		unset($arrayData['ajax'], $arrayData['controller'], $arrayData['options'], $arrayData['params'], $_POST['_CoreConfigRequest']);

		try {

			$arrayData['cache'] = $this->getCast()->bool($arrayData['cache']);
			$arrayData['isForm'] = $this->getCast()->bool($arrayData['isForm']);
			$arrayData['timeout'] = $this->getCast()->int($arrayData['timeout']);
			$arrayData['debug'] = $this->getCast()->bool($arrayData['debug']);

			if($arrayData['isForm'] === FALSE) {

				$arrayData['serialized'] = $this->getCast()->bool($arrayData['serialized']);
			}

			if($this->getCast()->equals(NULL, $arrayData['username'])) {

				$arrayData['username'] = NULL;
			}

			if($this->getCast()->equals(NULL, $arrayData['password'])) {

				$arrayData['password'] = NULL;
			}

			parent::getRequest()->addElement(array('ajaxRequest'), $arrayData);
		}

		catch(\Exception $e) {

			throw \Core\Uses\Exception('Error: Parametros inválidos para requisição. OBS: Invalid params in ajaxRequest.', E_ERROR, 100, __FILE__, __LINE__);
		}

		unset($arrayData);
	}

	final public function &_start($arrayRequest) {

		$Controller = parent::getController();
		$ReflectionObject =& new \Core\Libs\Reflection\ReflectionObject(&$Controller);
		$Response = parent::getResponse();

		parent::__construct();
		parent::getRequest()->add();

		parent::setNamespaceBase(substr(&$arrayRequest['namespace'], 1));
		parent::addParams($arrayRequest['url']['params']);
		parent::_addData($this->getPostsOfModels());
		parent::setUrl($arrayRequest['url']['base']);

		$ReflectionObject->getMethod('setAppUrl')->invokeOfClass('Core\Libs\MasterObject\MasterObject');

		$this->components = $ReflectionObject->getProperty('components')->mergedValuesOfMvcRequest(TRUE, FALSE);
		$Controller->controllerName = $ReflectionObject->getClass()->getShortName();
		$Controller->classController = $ReflectionObject->getClass()->getName();
		$Controller->actionOfController = $arrayRequest['action'];
		$Controller->controllerPath = $arrayRequest['controller']['path'];

		parent::getRequest()->addElement(array('name'), parent::getNamespaceBase());
		parent::getRequest()->addElement(array('requestType'), $arrayRequest['requestType']);
		parent::getRequest()->addElement(array('controller', 'class'), array('path' => $arrayRequest['controller']['path'], 'namespace' => $arrayRequest['controller']['namespace'], 'action' => $arrayRequest['action'], 'controllerName' => $Controller->controllerName));
		parent::getRequest()->addElement(array('options', 'return'), $arrayRequest['requestAction']);

		$typeRequestAction = $ReflectionObject->getMethod('getTypeOfResponse')->invokeOfClass('Core\Libs\MasterObject\MasterObject');

		if(!$ReflectionObject->getMethod('namespaceForMethodPermittedExists')->invokeOfClass('Core\Libs\MasterObject\MasterObject', array($Controller->classController))) {

			$arrayMethodsToAction = $ReflectionObject->getNamesOfMethodsInClass($Controller->classController, array('public'), FALSE, TRUE);
			$arrayMethodsToAction = array(key($arrayMethodsToAction) => array_diff((array)current($arrayMethodsToAction), $this->arrayCallbackMethods));
			$ReflectionObject->getMethod('addMethodsAllowed')->invokeOfClass('Core\Libs\MasterObject\MasterObject', array($arrayMethodsToAction, $Controller->classController));
			unset($arrayMethodsToAction);
		}

		$isAllowedControllerAction = $ReflectionObject->getMethod('isMethodAllowed')->invokeOfClass('Core\Libs\MasterObject\MasterObject', array($Controller->classController, &$arrayRequest['action']));

		if($isAllowedControllerAction) {

			if(parent::isValidAction($arrayRequest['action'])) {

				if(count($arrayRequest['url']['params']['numeric'])) {

					if($typeRequestAction !== 'returnOfController') {

						ob_start();
						$this->beforeFilter();
						call_user_func_array(array(&$Controller, &$arrayRequest['action']), $arrayRequest['url']['params']['numeric']);
						$this->afterFilter();
						$Controller->outputContent = ob_get_clean();
					}

					else {

						ob_start();
						$this->beforeFilter();
						$Controller->outputContent =& call_user_func_array(array(&$Controller, &$arrayRequest['action']), $arrayRequest['url']['params']['numeric']);
						$this->afterFilter();
						ob_end_clean();
					}
				}

				elseif(count($ReflectionObject->getClass()->getMethod(&$arrayRequest['action'])->getParameters()) === 0) {

					if($typeRequestAction !== 'returnOfController') {

						ob_start();
						$this->beforeFilter();
						call_user_func_array(array(&$Controller, &$arrayRequest['action']), array());
						$this->afterFilter();
						$Controller->outputContent = ob_get_clean();
					}

					else {

						ob_start();
						$this->beforeFilter();
						$Controller->outputContent =& call_user_func_array(array(&$Controller, &$arrayRequest['action']), array());
						$this->afterFilter();
						ob_end_clean();
					}
				}

				else {

					throw \Core\Uses\Exception('Error: Parametros necessários não passados a Action do Controller: - Controller: '.$namespaceController.', Action: '.$arrayRequest['action']);
				}
			}
		}

		else {

			throw \Core\Uses\Exception('Error: Action não encontrada no Controller. - Controller: ' . $Controller->classController . ', Action: ' . $arrayRequest['action']);
		}

		if($Response->RequestHeader()->isAjax() || (in_array('return', $arrayRequest['requestAction']) && ($typeRequestAction === 'returnOfController' || $typeRequestAction === 'responseOfController'))) {

			$this->autoRender = FALSE;
		}

		if($Response->RequestHeader()->isAjax() && $typeRequestAction === 'responseOfRequest') {

			$this->autoRender = TRUE;
		}

		parent::setController(&$Controller);

		$classView = $ReflectionObject->getProperty('classView')->getValue(NULL, NULL, NULL, TRUE, FALSE);
		$View = NULL;

		if(!$Controller->noRender && $typeRequestAction !== 'returnOfController' && $typeRequestAction !== 'responseOfController') {

			if($Controller->autoRender && $Response->isAllContentToResponseOfRequest()) {

				echo($Controller->outputContent);
				$Controller->outputContent = NULL;
			}

			if(!empty($classView)) {

				preg_match('/[a-zA-Z0-9\_]+$/', $classView, $match);
				$viewName = $match[0];
				$classViewPath =& parent::setRegistry()->getPathOfNamespace($classView, 'default', FALSE);
			}

			else {

				preg_match('/[a-zA-Z0-9\_]+$/', &$arrayRequest['view']['namespace'], $match);
				$viewName = $match[0];
				$classViewPath =& parent::getRegistry()->getPathOfNamespace($arrayRequest['view']['namespace'], 'default', FALSE);
			}

			if($classViewPath !== FALSE) {

				try {

					parent::getRegistry()->includeFilesRecursively($classViewPath, $arrayRequest['view']['namespace'], FALSE);
				}

				catch(\Exception $e) {

					throw \Core\Uses\Exception('Error: Extend(s) da Classe View e/ou Superclasse(s) não encontrado(s). Namespace: '.$arrayRequest['view']['namespace'].' - Path: '.$viewPath);
				}
			}

			else {

				throw \Core\Uses\Exception('Error: Classe View não encontrada. Namespace: '.$arrayRequest['view']['namespace'].' - Path: '.$viewPath);
			}

			$View = new $arrayRequest['view']['namespace']();
			$arrayRequest['view']['path'] = $classViewPath;
		}

		else {

			if($Response->isAllContentToResponseOfRequest() || $Controller->noRender) {

				if(ob_get_level() > 1) {

					$Controller->outputContent = ob_get_clean() . $Controller->outputContent;
				}

				if($Controller->autoRender && $Controller->noRender) {

					echo($Controller->outputContent);
					$Controller->outputContent = NULL;
				}
			}

			return;
		}

		parent::setView($View);

		if($typeRequestAction === FALSE || $typeRequestAction === 'responseOfView' || $typeRequestAction === 'returnOfView' || $typeRequestAction === 'responseOfRequest') {

			$View->_start(&$arrayRequest);
		}

		return;
	}

	public function beforeFilter() {

		
	}

	public function afterFilter() {

		
	}
}
?>